#include <iostream>
using namespace std;
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <assert.h>

#define OPT_NUM 64
#define NUM 1024
char lineCommand[NUM];
char *myargv[OPT_NUM]; // 指针数组：把切割后的字符串存放在这里

//实现echo $?
int lastCode = 0;
int lastSig = 0;

int main()
{
    while (1)
    {
        // 输入提示符号
        printf("用户名@主机名 当前路径# ");
        fflush(stdout); // 刷新缓冲区

        // 获取用户输入
        char *s = fgets(lineCommand, sizeof(lineCommand) - 1, stdin);
        assert(s != nullptr);
        (void)s;
        // 去除掉缓冲区中我们自己手动输入的换行符
        lineCommand[strlen(lineCommand) - 1] = 0;
        // printf("test:%s\n",lineCommand);

        //"ls -a -b"->"ls" "-a" "-b"
        // 字符串切割
        myargv[0] = strtok(lineCommand, " "); // 以空格进行切割
        // myargv[1] = strtok(nullptr," ");//在原来的字符串继续进行切割
        int i = 1;
        //让打印出来的数据带颜色
        if(myargv[0] != nullptr && strcmp(myargv[0], "ls") == 0){
            myargv[i++] = (char*)"--color=auto";
        }
        while (myargv[i++] = strtok(nullptr, " "))
            ;
        
        //处理cd路径的问题
        //如果是cd命令，就不让子进程去执行，而是让父进程自己执行
        if(myargv[0]!=nullptr && strcmp(myargv[0],"cd") == 0){
            if(myargv[1] != nullptr) chdir(myargv[1]);
            continue;
        }

        //处理echo $?
        if(myargv[0] != nullptr && myargv[1] != nullptr && strcmp(myargv[0],"echo") == 0){
            if(strcmp(myargv[1],"$?") == 0){
                printf("%d,%d\n",lastCode,lastSig);
            }
            else{
                printf("%s\n",myargv[1]);
            }
            continue;
        }


        // 测试是否成功切割
#ifdef DEBUG
        for (int i = 0; myargv[i]; i++)
        {
            printf("myargv[%d]:%s\n", i, myargv[i]);
        }
#endif

        //执行程序替换，让子进程去执行命令
        pid_t id = fork();
        assert(id != -1);

        if(id == 0){
            //子进程
            execvp(myargv[0],myargv);
            exit(1);
        }

        //父进程只要负责等待子进程退出即可
        int status = 0;
        pid_t ret =  waitpid(id,&status,0);
        assert(ret > 0);
        lastCode = ((status>>8)&0xff);
        lastSig = (status & 0x7f);
        // int status = 0;
        // while(1){
        //     int ret = waitpid(id,&status,WNOHANG);
        //     if(ret == 0){
        //         //todo
        //         sleep(1);
        //     }else if(ret > 0){
        //         printf("wait success,sig number:%d,exit code:%d\n",(status & 0x7f),(status>>8)&0xff);

        //     }else{
        //         printf("wait failed\n");

        //     }
        // }


    }
    return 0;
}